package com.ssy.lingxi.contract.esign.util;

import com.ssy.lingxi.contract.esign.exception.EsignError;
import com.ssy.lingxi.contract.esign.exception.EsignException;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;

/**
 * API工具类
 * @author yzc
 * @version 2.0.0
 * @date 2020/8/26
 */
public class ApiUtil {

    /**
     * 获取文件的md5值,并用base64编码返回字符
     * @param fis
     * @return
     */
    public static String fileMd5(InputStream fis) {
        String md5Base64 = null;
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            byte[] buffer = new byte[1024];
            int length = -1;
            while ((length = fis.read(buffer, 0, 1024)) != -1) {
                md5.update(buffer, 0, length);
            }
            byte[] md5Bytes = md5.digest();
            md5Base64 = new String(Base64.encodeBase64(md5Bytes));
        } catch (Exception e) {
            e.printStackTrace();
        }

        return md5Base64;
    }

    /**
     * 获取文件的md5值,并用base64编码返回字符
     * @param bytes
     * @return
     */
    public static String fileMd5(byte[] bytes) {
        String md5Base64 = null;
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            md5.update(bytes);
            byte[] md5Bytes = md5.digest();
            md5Base64 = new String(Base64.encodeBase64(md5Bytes));
        } catch (Exception e) {
            e.printStackTrace();
        }

        return md5Base64;
    }

    /**
     * 获取请求的ip
     * @param request
     * @return
     */
    public static String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个ip值，第一个ip才是真实ip
            if (ip.contains(",")) {
                ip = ip.split(",")[0];
            }
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 签名验签
     */
    public static boolean verifySign(String signture, String timestamp, String data, String secret) throws EsignException {
        String signData = timestamp + data;
        //计算签名方法
        String mysign = HmacSHA256(signData, secret);
        String lowerMysign = mysign.toLowerCase();
        System.out.println("mysign=" + lowerMysign);

        if (lowerMysign.equals(signture)) {
            System.out.println("验签成功");
            return true;
        } else {
            System.out.println("验签失败");
        }

        return false;
    }

    public static String HmacSHA256(String data, String secret) throws EsignException {
        byte[] keyByte = secret.getBytes(StandardCharsets.UTF_8);
        byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);

        SecretKeySpec secretKeySpec = new SecretKeySpec(keyByte, "HmacSHA256");
        try {
            Mac hmacSHA256 = Mac.getInstance("HmacSHA256");
            hmacSHA256.init(secretKeySpec);
            byte[] bytes = hmacSHA256.doFinal(dataBytes);

            StringBuilder sb = new StringBuilder();
            for (byte item : bytes) {
                sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
            }

            return sb.toString().toUpperCase();
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
            throw new EsignException(EsignError.builder().errMsg("HmacSHA256加签失败").build());
        }
    }
}
